#include "globals.h"
#include "symtab.h"
#include "code.h"
#include "cgen.h"

static int tmpOffset=0;

static void cGen(TreeNode * tree);

static void genStmt(TreeNode * tree){
  TreeNode *p1, *p2, *p3;
  int saveLoc1,saveLoc2,currentLoc;
  int loc;
  switch(tree->kind.stmt){
  case IfK:
    emitComment("-> if");
    p1=tree->child[0];
    p2=tree->child[1];
    p3=tree->child[2];
    cGen(p1);
    saveLoc1=emitSkip(1);
    emitComment("if: jump to else belongs here");
    cGen(p2);
    saveLoc2=emitSkip(1);
    emitComment("if: jump to end belongs here");
    currentLoc=emitSkip(0);
    emitBackup(saveLoc1);
    emitRM_Abs("JEQ",ac,currentLoc,"if: jmp to else");
    emitRestore();
    cGen(p3);
    currentLoc=emitSkip(0);
    emitBackup(saveLoc2);
    emitRM_Abs("LDA",pc,currentLoc,"jmp to end");
    emitRestore();
    emitComment("<- if");
    break;
  case RepeatK:
    emitComment("-> repeat");
    p1=tree->child[0];
    p2=tree->child[1];
    saveLoc1=emitSkip(0);
    emitComment("repeat: jump after body comes back here");
    cGen(p1);
    cGen(p2);
    emitRM_Abs("JEQ",ac,saveLoc1,"repeat: jmp back to body");
    emitComment("<- repeat");
    break;
  case AssignK:
    emitComment("-> assign");
    cGen(tree->child[0]);
    loc=st_lookup(tree->attr.name);
    emitRM("ST",ac,loc,gp,"assign: store value");
    emitComment("<- assign");
    break;
  case ReadK:
    emitRO("IN",ac,0,0,"read integer value");
    loc=st_lookup(tree->attr.name);
    emitRM("ST",ac,loc,gp,"read: store value");
    break;
  case WriteK:
    cGen(tree->child[0]);
    emitRO("OUT",ac,0,0,"write ac");
    break;
  default:
    printf("Error\n");
    break;
    
      }
}
static void genExp(TreeNode * tree){
  int loc;
  TreeNode *p1,*p2;
  
  switch(tree->kind.exp){
  case ConstK:
    emitComment("-> Const");
    emitRM("LDC",ac,tree->attr.val,0,"load const");
    emitComment("<- Const");
    break;
  case IdK:
    emitComment("-> Id");
    loc=st_lookup(tree->attr.name);
    emitRM("LD",ac,loc,gp,"load id value");
    emitComment("<- Id");
    break;
  case OpK:
    emitComment("-> Op");
    p1=tree->child[0];
    p2=tree->child[1];
    cGen(p1);
    emitRM("ST",ac,tmpOffset--,mp,"Op:push left");
    cGen(p2);
    emitRM("LD",ac1,++tmpOffset,mp,"Op:load left");

    switch(tree->attr.op){
    case PLUS:
      emitRO("ADD",ac,ac1,ac,"op +");
      break;
    case MINUS:
      emitRO("SUB",ac,ac1,ac,"op -");
      break;
    case MUL:
      emitRO("MUL",ac,ac1,ac,"op *");
      break;
    case DIV:
      emitRO("DIV",ac,ac1,ac,"op /");
      break;
    case LESS:
      emitRO("SUB",ac,ac1,ac,"op <");
      emitRM("JLT",ac,2,pc,"br if true");
      emitRM("LDC",ac,0,ac,"false case");
      emitRM("LDA",pc,1,pc,"unconditional jmp");
      emitRM("LDC",ac,1,ac,"true case");
      break;
    case EQUAL:
      emitRO("SUB",ac,ac1,ac,"op ==");
      emitRM("JEQ",ac,2,pc,"br if true");
      emitRM("LDC",ac,0,ac,"false case");
      emitRM("LDA",pc,1,pc,"unconditional jmp");
      emitRM("LDC",ac,1,ac,"true case");
      break;
    default:
      emitComment("BUG: Unknown operator");
      break;
      
    }
    emitComment("<- Op");
    break;

  default:
    break;
  }
  
}
static void cGen(TreeNode * tree){
  if(tree != NULL){
    //printf("here123\n");
    switch(tree->nodekind){
    case StmtK:
      genStmt(tree);
      break;
    case ExpK:
      genExp(tree);
      break;
    default:
      break;
    }
    cGen(tree->sibling);
  }
}
void codeGen(TreeNode * syntaxTree, char * codefile){
  char *s=malloc(strlen(codefile)+7);
  strcpy(s,"File: ");
  strcat(s,codefile);
  emitComment("Tiny Compilation to TM code");
  emitComment(s);
  emitComment("Standard prelude:");
  emitRM("LD",mp,0,ac,"load maxaddress from location 0");
  emitRM("ST",ac,0,ac,"clear location 0");
  emitComment("End of stardar prelude.");
  cGen(syntaxTree);
  emitComment("End of execcution");
  emitRO("HALT",0,0,0,"");
}
